<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <ul class="list" id="ullist">
            <!-- 注释内容 -->
            <li class="item">内容1</li>
            <li class="item">内容2</li>
            <li class="item">内容3</li>
            <li class="item">内容4</li>
            <li class="item">内容5</li>
        </ul>
    </div>

    <script>

        // 准备知识点
        // 1) [].slice.call(lis): 将伪数组转换为真数组

        // var arr = [3, 9, 2, 7, 4];
        // // slice 方法,数组方法
        // console.log( arr.slice(1, 3) )// 从下标为1的位置开始截取,截取到下标为3的位置,但不包含3这个位置
        // console.log( arr.slice(1) ) // 从下标为1的位置截取,截取到数组末尾
        // console.log( arr.slice() ) // 从下标为0的位置开始截取,截取到数组默认

        // // call方法
        // let obj = {
        //     name: "二哈",
        //     eat: function() {
        //         console.log('很能吃', this)
        //     }
        // }
        // obj.eat(); // 此时方法中的this是obj,谁调用了方法,this就指向谁

        // let obj1 = {
        //     name: '旺财'
        // }
        // obj.eat.call(obj1); // 调用eat方法的obj本来是this的指向,但是又.call了,call方法将this的指向只给obj1了

        // // lis 获取到的是一个伪数组,这个伪数组不能调用forEach,没有这个方法
        // let lis = document.getElementsByClassName('item')
        // console.log(lis);

        // const arr1 = [].slice.call(lis);
        // console.log(arr1);

        // // arr1.forEach(() => {})


        // 2) node.nodeType: 得到节点类型
        // 在页面当中总共有12种节点类型,我们关注的就4种类
        // 元素节点、文本节点、属性节点、注释节点


        // let ulNode = document.getElementById('ullist');

        // console.log(ulNode)
        // console.dir(ulNode)

        // console.log(ulNode.attributes)
        // console.log(ulNode.attributes[0])
        // console.dir(ulNode.attributes[0])


        // console.log(ulNode.childNodes); // 拿到所有的子节点

        // console.log(ulNode.childNodes[1]); // 拿到注释节点
        // console.dir(ulNode.childNodes[1]);

        // console.log(ulNode.children) // 拿到的是所有的子元素,拿的不是节点
        // console.log(ulNode.children[0])
        // console.log(ulNode.children[0].childNodes)
        // console.log(ulNode.children[0].childNodes[0])
        // console.dir(ulNode.children[0].childNodes[0])


        //              nodeName    nodeType    nodeValue
        // 元素节点     元素名大写       1          null
        // 属性节点      属性名          2         属性值
        // 注释节点      #comment       8        注释的内容
        // 文本节点      #text          3         文本内容











        // 3) Object.defineProperty(obj, propName, {}): 给对象添加 / 修改属性(指定描述符)

        let obj = {
            name: '张三'
        }
        // 注意: value、writable 和 get、set 互斥
        Object.defineProperty(obj, 'age', {
            // value: 55, // 配属性的置值
            // writable: true, // 配置属性的值是否可以被修改
            configurable: false, // 配置属性是否可以被定义(是否可以被删除)
            enumerable: false, // 配置属性是否可枚举(能不能被forin遍历出来)
            get() {
                return 222
            },
            set(val) {
                console.log('val -> ', val)
            },
        })

        console.log(obj)

        obj.age = 66

        console.log(obj)

        delete obj.age

        console.log(obj)

        for (const key in obj) {
            console.log('key -> ', key)
        }

        console.log(obj.age)

        obj.age = 230





        // 4) Object.keys(obj): 得到对象自身可枚举的属性名的数组，从而遍历拿到对象中所有的属性

        // let obj = {
        //     name: '张三',
        //     age: 22
        // }

        // // Object.keys()
        // // 功能: .keys()是一个Object的方法,当Object调用这个方法的时候需要传一个对象
        // //      得到的结果是这个对象的[可枚举属性]组成的数组
        // // 参数: 对象
        // // 返回值: 数组

        // let arr = Object.keys(obj);
        // console.log(arr)

        // Object.keys(obj).forEach(item => {
        //     console.log(item, obj[item])
        // })


        // 5) obj.hasOwnProperty(prop): 判断prop是否是obj自身的属性


        // Object.prototype.hasOwnProperty 是一个方法
        // 参数: 参数是一个字符串
        // 返回值: 布尔值
        // 功能: 判断传入的参数是不是 当前调用对象的[自身属性]

        // Object.prototype.job = '看门'

        // let dog = {
        //     name: '二哈',
        //     age: 3
        // }

        // console.log(dog.name);
        // console.log(dog.job);

        // console.log( dog.hasOwnProperty('name') )
        // console.log( dog.hasOwnProperty('job') )





        // 6) documentfragment 文档碎片
        // 页面中现在有一个ul和它的五个子元素li,想要修改5个li的内容变成"哈哈"
        // 这是我们使用js最原始的做法:
        // let lis = document.getElementsByClassName('item');
        // [].slice.call(lis).forEach(item => {
        //     item.innerText = "哈哈"
        // })
        // 这样修改每个li会循环修改,每次修改一个li都会引发重排和重绘
        // 如果li过多,那么此时通过循环修改li中的内容,会大大影响浏览器的性能
        // 这就是原生效率不高的原因
        // 重排: 元素的位置发生变化会引发重排
        // 重绘: 元素的大小和样式发生变化会引发重绘

        // documentfragment 是文档碎片,可以理解为一个容器,这个容器存在于内存当中,且里面是放DOM元素的
        // 那么当大量的页面DOM绘制的时候,此时可以把页面中的DOM放到这个容器中去
        // 页面就没有内容显示了,所有的DOM在这个容器中,在内存中,
        // 此时改变这些DOM的时候,并不会引发大量的重排和重绘,因为是在内存中修改DOM的内容的,不涉及渲染
        // 当在内存中修改完内容之后,在把这个容器里面的DOM元素,放回到页面里面
        // 这样性能就提升了

        // // 创建fragment容器
        // const fragment = document.createDocumentFragment();

        // // 获取页面内容
        // const app = document.getElementById('app');

        // let child; // 临时存放子节点使用

        // // while小括号跟一个布尔值,如果不是布尔值,转成布尔值
        // // 现在while小括号中放了一个赋值语句,是一个表达式,表达式是有值的
        // // 将这个表达式的值转成布尔值判断就行
        // while (child = app.childNodes[0]) {
        //     // console.log(child);
        //     // console.log(app.childNodes[0]);
        //     fragment.appendChild(child);
        // }

        // // console.log(app.childNodes)
        // // console.log(fragment)

        // console.log(fragment)
        // console.log(fragment.children)
        // console.log(fragment.children[0])
        // console.log(fragment.children[0].children); // 拿到5个li组成的伪数组

        // [].slice.call(fragment.children[0].children).forEach(item => {
        //     item.innerText = "哈哈"; // 此时修改li的文本是在内存中,是在容器里
        // })

        // console.log(fragment) // 此时已经改完了所有的DOM了,现在该把容器中的内容交还给页面了

        // app.appendChild(fragment);




    </script>
</body>

</html>